本文档主要用于绘制降水评分或温度误差的空间分布情况。可以作为绘制地图上散点图的例子。注意下面几个问题:
利用sf和gemo_sf来绘制地图,coord_sf在有地图投影的时候,设置其它的地图投影,空间范围会起到不好作用,建议先把data.frame转为sf的数据结构,然后改变该结构的地图投影,并用st_crop剪裁。
用同时设置fill和color,这样才能使得绘制的图形具有相同的颜色。
通过scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) + scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE)来设置,但这里要注意有坑,要设置好drop=FALSE,因为ggplot2默认不会显示出没有类的level,这样会导致颜色标错。
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=12, ymax=54)
china_map <- st_transform(china_map, 4508)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

读入和处理数据
# 读入站点信息数据
station_info <- read_micaps_3("./data/forecast_scores/stat10461.txt")
station_info <- station_info$dataV
station_info <- station_info %>% select(ID, lon, lat)
head(station_info)
# the whole year score
file <- "./data/forecast_scores/result/rain24/SCMOC/20200301-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "小雨", "中雨", "大雨", "暴雨", "大暴雨", "特大暴雨",
"小雪", "中雪", "大雪", "暴雪",
"LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250",
"一般性降水", "暴雨雪以上", "RainOrNot")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.900024"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% select(
"ID", "LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250", "RainOrNot") %>%
inner_join(station_info, by="ID")
scores
绘制降水评分分布图
You can also embed plots, for example:
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map, 4326)
points <- scores %>% filter(!is.na(LE50))
# %>% filter(LE50 >= 0.05 & LE50 <= 0.25)
colors <- paletteer_d("ggsci::legacy_tron",7,direction=-1,type="continuous")
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_point(data=points, size=3, aes(x=lon, y=lat, color=LE50)) +
# 对于非等间距的breaks支持并不好, 会造成颜色非常相近
#scale_colour_fermenter(name=NULL, breaks=c(0.005, 0.05, 0.01, 0.15, 0.20, 0.25), palette = "Accent") +
#scale_color_binned(name=NULL, breaks=c(0.005, 0.05, 0.01, 0.15, 0.20, 0.25), type="viridis") +
# scale_color_stepn这个函数绘制的图像一直不对
# 可以参考https://stackoverflow.com/questions/66318404/how-to-use-specific-filling-colors-when-using-scale-fill-binned?noredirect=1&lq=1
# 但比较复杂.
#scale_color_stepsn(name=NULL, breaks=c(0.005, 0.05, 0.1, 0.15, 0.20, 0.25), limits=c(0,0.3),
# values=scales::rescale(c(0.0025, 0.275, 0.75, 0.125,0.175,0.225,0.275),from=c(0,0.3)),
# colours=paletteer_d("ggsci::legacy_tron",7,direction=-1,type="continuous"),
# na.value = "white")+
#scale_color_stepsn(name=NULL, breaks=c(0.005, 0.05, 0.1, 0.15, 0.20, 0.25), limits=c(0.005,0.25),
# values=scales::rescale(c(0.005, 0.05, 0.1, 0.15, 0.20, 0.25)),
# colours=paletteer_d("ggsci::legacy_tron",5,direction=-1,type="continuous"),
# na.value = "white")+
# 这个解决方案是目标最稳妥的解决方案参考
# https://stackoverflow.com/questions/65627153/specify-bin-colours-in-binned-colour-fill-scales
binned_scale("color", "foo", ggplot2:::binned_pal(scales::manual_pal(colors)),
guide="coloursteps", breaks=c(0.005, 0.05, 0.1, 0.15, 0.20, 0.25),
limits=c(0.0,1.0), show.limits=TRUE) +
#guides(fill = guide_legend(nrow = 1, override.aes=list(size=10))) +
coord_sf(expand = FALSE, ylim=c(25,30), xlim=c(110, 120)) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年3月至2021年2月全国10246站暴雨(>=50mm)TS评分",
caption = "Origin: National Meteorological Center NMC-WFT, 检验大数据分析平台(http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE) +
theme(legend.position = "right")

试验geom_sf和geom_point混合使用
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map, 4326)
points <- scores %>% filter(!is.na(LE50))
colors <- paletteer::paletteer_d("ggsci::legacy_tron",7,direction=-1,type="continuous")
ggplot() +
geom_sf(data=china_map, fill="white", size=0.1) +
geom_point(data=points, size=0.6, aes(x=lon, y=lat, color=LE50)) +
# 这个解决方案是目标最稳妥的解决方案参考
# https://stackoverflow.com/questions/65627153/specify-bin-colours-in-binned-colour-fill-scales
binned_scale("color", "foo", ggplot2:::binned_pal(scales::manual_pal(colors)),
guide="coloursteps", breaks=c(0.005, 0.05, 0.1, 0.15, 0.20, 0.25),
limits=c(0.0,1.0), show.limits=TRUE) +
#guides(fill = guide_legend(nrow = 1, override.aes=list(size=10))) +
coord_sf(crs=st_crs(4508), expand = FALSE, xlim=c(90,124), ylim=c(20, 44), default=TRUE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年3月至2021年2月全国10246站暴雨(>=50mm)TS评分",
caption = "Origin: National Meteorological Center NMC-WFT, 检验大数据分析平台(http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE) +
theme(legend.position = "right")

# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 0.01, 0.1, 0.2, 0.4, 0.6, Inf)
points <- filter(points, !is.na(points$LE50)) %>%
mutate(LE50=cut(LE50,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c("Gray","#F6F964","#007500","blue","magenta","#F01400")
labels <- levels(points$LE50)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=LE50, color=LE50)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年3月1日至2021年2月28日全国10246站24h时效暴雨(>=50mm)TS评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 50, 60, 70, 80, 90, Inf)
points <- filter(points, !is.na(points$RainOrNot)) %>%
mutate(RainOrNot=cut(RainOrNot,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- rev(c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33'))
labels <- levels(points$RainOrNot)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=RainOrNot, color=RainOrNot)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年3月1日至2021年2月28日全国10246站24h时效晴雨准确率评分(%)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

各个季节的降水预报质量
#===============================
#
# 春季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/rain24/SCMOC/20200301-2020053100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "小雨", "中雨", "大雨", "暴雨", "大暴雨", "特大暴雨",
"小雪", "中雪", "大雪", "暴雪",
"LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250",
"一般性降水", "暴雨雪以上", "RainOrNot")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.900024"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% select(
"ID", "LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250", "RainOrNot") %>%
inner_join(station_info, by="ID")
#
# 绘制强降水预报质量分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 0.01, 0.1, 0.2, 0.4, 0.6, Inf)
points <- filter(points, !is.na(points$LE25)) %>%
mutate(LE50=cut(LE25,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c("Gray","#F6F964","#007500","blue","magenta","#F01400")
labels <- levels(points$LE50)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=LE50, color=LE50)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年3月1日至2020年5月31日全国10246站24h时效大雨(>=25mm)TS评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 绘制晴雨预报质量分布图
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 50, 60, 70, 80, 90, Inf)
points <- filter(points, !is.na(points$RainOrNot)) %>%
mutate(RainOrNot=cut(RainOrNot,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- rev(c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33'))
labels <- levels(points$RainOrNot)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=RainOrNot, color=RainOrNot)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年3月1日至2020年5月31日全国10246站24h时效晴雨准确率评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 夏季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/rain24/SCMOC/20200601-2020083100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "小雨", "中雨", "大雨", "暴雨", "大暴雨", "特大暴雨",
"小雪", "中雪", "大雪", "暴雪",
"LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250",
"一般性降水", "暴雨雪以上", "RainOrNot")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.900024"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% select(
"ID", "LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250", "RainOrNot") %>%
inner_join(station_info, by="ID")
#
# 绘制强降水预报质量分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 0.01, 0.1, 0.2, 0.4, 0.6, Inf)
points <- filter(points, !is.na(points$LE50)) %>%
mutate(LE50=cut(LE50,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c("Gray","#F6F964","#007500","blue","magenta","#F01400")
labels <- levels(points$LE50)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=LE50, color=LE50)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年6月1日至2020年8月31日全国10246站24h时效暴雨(>=50mm)TS评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 绘制晴雨预报质量分布图
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 50, 60, 70, 80, 90, Inf)
points <- filter(points, !is.na(points$RainOrNot)) %>%
mutate(RainOrNot=cut(RainOrNot,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- rev(c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33'))
labels <- levels(points$RainOrNot)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=RainOrNot, color=RainOrNot)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年6月1日至2020年8月31日全国10246站24h时效晴雨准确率评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 秋季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/rain24/SCMOC/20200901-2020113000.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "小雨", "中雨", "大雨", "暴雨", "大暴雨", "特大暴雨",
"小雪", "中雪", "大雪", "暴雪",
"LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250",
"一般性降水", "暴雨雪以上", "RainOrNot")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.900024"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% select(
"ID", "LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250", "RainOrNot") %>%
inner_join(station_info, by="ID")
#
# 绘制强降水预报质量分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 0.01, 0.1, 0.2, 0.4, 0.6, Inf)
points <- filter(points, !is.na(points$LE25)) %>%
mutate(LE50=cut(LE25,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c("Gray","#F6F964","#007500","blue","magenta","#F01400")
labels <- levels(points$LE50)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=LE50, color=LE50)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年9月1日至2020年11月30日全国10246站24h时效大雨(>=25mm)TS评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 绘制晴雨预报质量分布图
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 50, 60, 70, 80, 90, Inf)
points <- filter(points, !is.na(points$RainOrNot)) %>%
mutate(RainOrNot=cut(RainOrNot,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- rev(c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33'))
labels <- levels(points$RainOrNot)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=RainOrNot, color=RainOrNot)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年9月1日至2020年11月30日全国10246站24h时效晴雨准确率评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 冬季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/rain24/SCMOC/20201201-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "小雨", "中雨", "大雨", "暴雨", "大暴雨", "特大暴雨",
"小雪", "中雪", "大雪", "暴雪",
"LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250",
"一般性降水", "暴雨雪以上", "RainOrNot")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.900024"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% select(
"ID", "LE0p1", "LE10", "LE25", "LE50", "LE100", "LE250", "RainOrNot") %>%
inner_join(station_info, by="ID")
#
# 绘制强降水预报质量分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 0.01, 0.1, 0.2, 0.4, 0.6, Inf)
points <- filter(points, !is.na(points$LE25)) %>%
mutate(LE50=cut(LE25,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c("Gray","#F6F964","#007500","blue","magenta","#F01400")
labels <- levels(points$LE50)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=LE50, color=LE50)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报评分分布图",
subtitle = "2020年12月1日至2021年2月28日全国10246站24h时效大雨(>=25mm)TS评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 绘制晴雨预报质量分布图
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 50, 60, 70, 80, 90, Inf)
points <- filter(points, !is.na(points$RainOrNot)) %>%
mutate(RainOrNot=cut(RainOrNot,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- rev(c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33'))
labels <- levels(points$RainOrNot)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=RainOrNot, color=RainOrNot)) +
scale_color_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, labels=labels, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国定量降水预报质量分布图",
subtitle = "2020年12月1日至2021年2月28日全国10246站24h时效晴雨准确率评分",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

高温/低温预报准确率
#===============================
#
# 全年预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmx-neib-height/SCMOC/20200301-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制高温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最高气温预报误差分布图",
subtitle = "2020年3月1日至2021年2月28日全国10246站24h时效日最高温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmi-neib-height/SCMOC/20200301-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制低温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
labels <- levels(points$MAE)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最低气温预报误差分布图",
subtitle = "2020年3月1日至2021年2月28日全国10246站24h时效日最低温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 春季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmx-neib-height/SCMOC/20200301-2020053100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制高温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最高气温预报误差分布图",
subtitle = "2020年3月1日至2020年5月31日全国10246站24h时效日最高温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmi-neib-height/SCMOC/20200301-2020053100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制低温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
labels <- levels(points$MAE)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最低气温预报误差分布图",
subtitle = "2020年3月1日至2020年5月31日全国10246站24h时效日最低温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 夏季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmx-neib-height/SCMOC/20200601-2020083100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制高温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最高气温预报误差分布图",
subtitle = "2020年6月1日至2020年8月31日全国10246站24h时效日最高温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmi-neib-height/SCMOC/20200601-2020083100.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制低温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
labels <- levels(points$MAE)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最低气温预报误差分布图",
subtitle = "2020年6月1日至2020年8月31日全国10246站24h时效日最低温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 秋季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmx-neib-height/SCMOC/20200901-2020113000.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制高温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最高气温预报误差分布图",
subtitle = "2020年9月1日至2020年11月30日全国10246站24h时效日最高温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmi-neib-height/SCMOC/20200901-2020113000.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制低温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
labels <- levels(points$MAE)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最低气温预报误差分布图",
subtitle = "2020年9月1日至2020年11月30日全国10246站24h时效日最低温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#===============================
#
# 冬季预报质量
#===============================
#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmx-neib-height/SCMOC/20201201-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制高温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最高气温预报误差分布图",
subtitle = "2020年12月1日至2021年2月28日全国10246站24h时效日最高温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

#
# 读入数据文件
# the score data
file <- "./data/forecast_scores/result/tmi-neib-height/SCMOC/20201201-2021022800.024"
# 读入数据, ID为字符型, 以便与station_info对应.
col_names <- c("ID", "MAE")
col_types=cols(.default = col_double(), "ID"=col_character())
scores <- read_delim(file, delim="\t", col_names=col_names,
na=c("--", "999.9"), col_types=col_types)
# 只使用后面几列的数据, 并结合站点经纬度信息
scores <- scores %>% inner_join(station_info, by="ID")
#
# 绘制低温预报误差分布图
# map background
china_map <- st_read(
system.file("extdata/bou2_4p.shp", package="nmcMetResources"),
stringsAsFactors=FALSE, quiet=TRUE)
china_map <- st_set_crs(china_map,4326)
china_map <- st_crop(china_map, xmin=73, xmax=135, ymin=17, ymax=54)
china_map <- st_transform(china_map, 4508)
points <- st_as_sf(scores, coords = c("lon", "lat"), crs=4326)
breaks <- c(-Inf, 1.0, 1.4, 1.6, 2.0, 2.5, 3.0, Inf)
points <- filter(points, !is.na(points$MAE)) %>%
mutate(MAE=cut(MAE,breaks,right=FALSE))
points <- st_crop(points, xmin=73, xmax=135, ymin=17, ymax=54)
points <- st_transform(points, 4508)
values <- c('#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f')
labels <- levels(points$MAE)
ggplot() +
geom_sf(data=china_map, fill="antiquewhite1") +
geom_sf(data=points, shape=23, size=0.6, alpha=0.8,
aes(fill=MAE, color=MAE)) +
scale_color_manual(name=NULL, values=values, drop=FALSE) +
scale_fill_manual(name=NULL, values=values, drop=FALSE) +
guides(color = guide_legend(nrow = 1, override.aes=list(size=12))) +
coord_sf(expand = FALSE) +
annotation_scale(location = "bl", width_hint = 0.3) +
annotation_north_arrow(location = "bl", which_north = "true",
pad_x = unit(0.75, "in"), pad_y = unit(0.5, "in"),
style = north_arrow_fancy_orienteering) +
labs(x = NULL, y = NULL, fill = NULL,
title = "全国日最低气温预报误差分布图",
subtitle = "2020年12月1日至2021年2月28日全国10246站24h时效日最低温平均绝对误差(度)",
caption = "Origin: NMC-WFT 检验大数据分析平台 (http://10.1.64.146/nvsnew)") +
theme_ipsum_rc(grid=TRUE, base_size=12,
plot_title_size=24, subtitle_size=18, caption_size=12) +
theme(legend.position = "top", legend.text = element_text(size=12))

LS0tCnRpdGxlOiAi5Lit5Zu95Yy65Z+f6ZmN5rC05Y+K5rip5bqm6aKE5oql5oqA5ben5YiG5biD5Zu+IgphdXRob3I6ICJLYW4gRGFpLCBXZWkgUWluLCBMaSBuaW5hIgpkYXRlOiAiMjAyMS80LzgiCkNKS21haW5mb250OiBNaWNyb3NvZnQgWWFIZWkKb3V0cHV0OgogIHBkZl9kb2N1bWVudDoKICAgIGluY2x1ZGVzOgogICAgICBoZWFkZXItaW5jbHVkZXM6CiAgICAgICAgLSBcdXNlcGFja2FnZXt4ZUNKS30KICAgICAga2VlcF90ZXg6IHllcwogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoK5pys5paH5qGj5Li76KaB55So5LqO57uY5Yi26ZmN5rC06K+E5YiG5oiW5rip5bqm6K+v5beu55qE56m66Ze05YiG5biD5oOF5Ya144CC5Y+v5Lul5L2c5Li657uY5Yi25Zyw5Zu+5LiK5pWj54K55Zu+55qE5L6L5a2Q44CC5rOo5oSP5LiL6Z2i5Yeg5Liq6Zeu6aKY77yaCgotICAg5Yip55Soc2blkoxnZW1vX3Nm5p2l57uY5Yi25Zyw5Zu+77yMY29vcmRfc2blnKjmnInlnLDlm77mipXlvbHnmoTml7blgJnvvIzorr7nva7lhbblroPnmoTlnLDlm77mipXlvbHvvIznqbrpl7TojIPlm7TkvJrotbfliLDkuI3lpb3kvZznlKjvvIzlu7rorq7lhYjmiopkYXRhLmZyYW1l6L2s5Li6c2bnmoTmlbDmja7nu5PmnoTvvIznhLblkI7mlLnlj5jor6Xnu5PmnoTnmoTlnLDlm77mipXlvbHvvIzlubbnlKhzdF9jcm9w5Ymq6KOB44CCCgotICAg55So5ZCM5pe26K6+572uZmlsbOWSjGNvbG9y77yM6L+Z5qC35omN6IO95L2/5b6X57uY5Yi255qE5Zu+5b2i5YW35pyJ55u45ZCM55qE6aKc6Imy44CCCgotICAg6YCa6L+Hc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKyBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGxhYmVscz1sYWJlbHMsIGRyb3A9RkFMU0Up5p2l6K6+572u77yM5L2G6L+Z6YeM6KaB5rOo5oSP5pyJ5Z2R77yM6KaB6K6+572u5aW9ZHJvcD1GQUxTRe+8jOWboOS4umdncGxvdDLpu5jorqTkuI3kvJrmmL7npLrlh7rmsqHmnInnsbvnmoRsZXZlbO+8jOi/meagt+S8muWvvOiHtOminOiJsuagh+mUmeOAggoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBsb2FkIGxpYnJhcmllcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzZikKbGlicmFyeShnZ3NwYXRpYWwpCmxpYnJhcnkocGFsZXR0ZWVyKQpsaWJyYXJ5KGhyYnJ0aGVtZXMpCgpsaWJyYXJ5KG5tY01ldElPKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xMiwgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCiMjIOivu+WFpeWSjOWkhOeQhuaVsOaNrgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyDor7vlhaXnq5nngrnkv6Hmga/mlbDmja4Kc3RhdGlvbl9pbmZvIDwtIHJlYWRfbWljYXBzXzMoIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvc3RhdDEwNDYxLnR4dCIpCnN0YXRpb25faW5mbyA8LSBzdGF0aW9uX2luZm8kZGF0YVYKc3RhdGlvbl9pbmZvIDwtIHN0YXRpb25faW5mbyAlPiUgc2VsZWN0KElELCBsb24sIGxhdCkKaGVhZChzdGF0aW9uX2luZm8pCmBgYAoKYGBge3J9CgojIHRoZSB3aG9sZSB5ZWFyIHNjb3JlCmZpbGUgPC0gIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvcmVzdWx0L3JhaW4yNC9TQ01PQy8yMDIwMDMwMS0yMDIxMDIyODAwLjAyNCIKCiMg6K+75YWl5pWw5o2uLCBJROS4uuWtl+espuWeiywg5Lul5L6/5LiOc3RhdGlvbl9pbmZv5a+55bqULgpjb2xfbmFtZXMgPC0gYygiSUQiLCAi5bCP6ZuoIiwgIuS4rembqCIsICLlpKfpm6giLCAi5pq06ZuoIiwgIuWkp+aatOmbqCIsICLnibnlpKfmmrTpm6giLAogICAgICAgICAgICAgIuWwj+mbqiIsICLkuK3pm6oiLCAi5aSn6ZuqIiwgIuaatOmbqiIsIAogICAgICAgICAgICAgIkxFMHAxIiwgIkxFMTAiLCAiTEUyNSIsICJMRTUwIiwgIkxFMTAwIiwgIkxFMjUwIiwKICAgICAgICAgICAgICLkuIDoiKzmgKfpmY3msLQiLCAi5pq06Zuo6Zuq5Lul5LiKIiwgIlJhaW5Pck5vdCIpCmNvbF90eXBlcz1jb2xzKC5kZWZhdWx0ID0gY29sX2RvdWJsZSgpLCAiSUQiPWNvbF9jaGFyYWN0ZXIoKSkKc2NvcmVzIDwtICByZWFkX2RlbGltKGZpbGUsIGRlbGltPSJcdCIsIGNvbF9uYW1lcz1jb2xfbmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICBuYT1jKCItLSIsICI5OTkuOTAwMDI0IiksIGNvbF90eXBlcz1jb2xfdHlwZXMpCgojIOWPquS9v+eUqOWQjumdouWHoOWIl+eahOaVsOaNriwg5bm257uT5ZCI56uZ54K557uP57qs5bqm5L+h5oGvCnNjb3JlcyA8LSBzY29yZXMgJT4lIHNlbGVjdCgKICAiSUQiLCAiTEUwcDEiLCAiTEUxMCIsICJMRTI1IiwgIkxFNTAiLCAiTEUxMDAiLCAiTEUyNTAiLCAiUmFpbk9yTm90IikgJT4lCiAgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgpzY29yZXMKYGBgCgojIyDnu5jliLbpmY3msLTor4TliIbliIbluIPlm74KCllvdSBjYW4gYWxzbyBlbWJlZCBwbG90cywgZm9yIGV4YW1wbGU6CgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0KCiMgbWFwIGJhY2tncm91bmQKY2hpbmFfbWFwIDwtIHN0X3JlYWQoCiAgc3lzdGVtLmZpbGUoImV4dGRhdGEvYm91Ml80cC5zaHAiLCBwYWNrYWdlPSJubWNNZXRSZXNvdXJjZXMiKSwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcXVpZXQ9VFJVRSkKY2hpbmFfbWFwIDwtIHN0X3NldF9jcnMoY2hpbmFfbWFwLCA0MzI2KQoKcG9pbnRzIDwtIHNjb3JlcyAlPiUgZmlsdGVyKCFpcy5uYShMRTUwKSkKIyAgICAgICU+JSBmaWx0ZXIoTEU1MCA+PSAwLjA1ICYgTEU1MCA8PSAwLjI1KQpjb2xvcnMgPC0gcGFsZXR0ZWVyX2QoImdnc2NpOjpsZWdhY3lfdHJvbiIsNyxkaXJlY3Rpb249LTEsdHlwZT0iY29udGludW91cyIpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3BvaW50KGRhdGE9cG9pbnRzLCBzaXplPTMsIGFlcyh4PWxvbiwgeT1sYXQsIGNvbG9yPUxFNTApKSArCiAgCiAgIyDlr7nkuo7pnZ7nrYnpl7Tot53nmoRicmVha3PmlK/mjIHlubbkuI3lpb0sIOS8mumAoOaIkOminOiJsumdnuW4uOebuOi/kQogICNzY2FsZV9jb2xvdXJfZmVybWVudGVyKG5hbWU9TlVMTCwgYnJlYWtzPWMoMC4wMDUsIDAuMDUsIDAuMDEsIDAuMTUsIDAuMjAsIDAuMjUpLCBwYWxldHRlID0gIkFjY2VudCIpICsgCiAgCiAgI3NjYWxlX2NvbG9yX2Jpbm5lZChuYW1lPU5VTEwsIGJyZWFrcz1jKDAuMDA1LCAwLjA1LCAwLjAxLCAwLjE1LCAwLjIwLCAwLjI1KSwgdHlwZT0idmlyaWRpcyIpICsKICAKICAjIHNjYWxlX2NvbG9yX3N0ZXBu6L+Z5Liq5Ye95pWw57uY5Yi255qE5Zu+5YOP5LiA55u05LiN5a+5CiAgIyDlj6/ku6Xlj4LogINodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82NjMxODQwNC9ob3ctdG8tdXNlLXNwZWNpZmljLWZpbGxpbmctY29sb3JzLXdoZW4tdXNpbmctc2NhbGUtZmlsbC1iaW5uZWQ/bm9yZWRpcmVjdD0xJmxxPTEKICAjIOS9huavlOi+g+Wkjeadgi4KICAjc2NhbGVfY29sb3Jfc3RlcHNuKG5hbWU9TlVMTCwgYnJlYWtzPWMoMC4wMDUsIDAuMDUsIDAuMSwgMC4xNSwgMC4yMCwgMC4yNSksIGxpbWl0cz1jKDAsMC4zKSwKICAjICAgICAgICAgICAgICAgICAgIHZhbHVlcz1zY2FsZXM6OnJlc2NhbGUoYygwLjAwMjUsIDAuMjc1LCAwLjc1LCAwLjEyNSwwLjE3NSwwLjIyNSwwLjI3NSksZnJvbT1jKDAsMC4zKSksCiAgIyAgICAgICAgICAgICAgICAgICBjb2xvdXJzPXBhbGV0dGVlcl9kKCJnZ3NjaTo6bGVnYWN5X3Ryb24iLDcsZGlyZWN0aW9uPS0xLHR5cGU9ImNvbnRpbnVvdXMiKSwKICAjICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIndoaXRlIikrCiAgI3NjYWxlX2NvbG9yX3N0ZXBzbihuYW1lPU5VTEwsIGJyZWFrcz1jKDAuMDA1LCAwLjA1LCAwLjEsIDAuMTUsIDAuMjAsIDAuMjUpLCBsaW1pdHM9YygwLjAwNSwwLjI1KSwKICAjICAgICAgICAgICAgICAgICAgdmFsdWVzPXNjYWxlczo6cmVzY2FsZShjKDAuMDA1LCAwLjA1LCAwLjEsIDAuMTUsIDAuMjAsIDAuMjUpKSwKICAjICAgICAgICAgICAgICAgICAgY29sb3Vycz1wYWxldHRlZXJfZCgiZ2dzY2k6OmxlZ2FjeV90cm9uIiw1LGRpcmVjdGlvbj0tMSx0eXBlPSJjb250aW51b3VzIiksCiAgIyAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIndoaXRlIikrCgogICMg6L+Z5Liq6Kej5Yaz5pa55qGI5piv55uu5qCH5pyA56iz5aal55qE6Kej5Yaz5pa55qGI5Y+C6ICDCiAgIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82NTYyNzE1My9zcGVjaWZ5LWJpbi1jb2xvdXJzLWluLWJpbm5lZC1jb2xvdXItZmlsbC1zY2FsZXMKICBiaW5uZWRfc2NhbGUoImNvbG9yIiwgImZvbyIsIGdncGxvdDI6OjpiaW5uZWRfcGFsKHNjYWxlczo6bWFudWFsX3BhbChjb2xvcnMpKSwKICAgICAgICAgICAgICAgZ3VpZGU9ImNvbG91cnN0ZXBzIiwgYnJlYWtzPWMoMC4wMDUsIDAuMDUsIDAuMSwgMC4xNSwgMC4yMCwgMC4yNSksCiAgICAgICAgICAgICAgIGxpbWl0cz1jKDAuMCwxLjApLCBzaG93LmxpbWl0cz1UUlVFKSArIAogIAogICNndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMCkpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFLCB5bGltPWMoMjUsMzApLCB4bGltPWMoMTEwLCAxMjApKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpeivhOWIhuWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciOiHszIwMjHlubQy5pyI5YWo5Zu9MTAyNDbnq5nmmrTpm6goPj01MG1tKVRT6K+E5YiGIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOYXRpb25hbCBNZXRlb3JvbG9naWNhbCBDZW50ZXIgTk1DLVdGVCwg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoK6K+V6aqMZ2VvbV9zZuWSjGdlb21fcG9pbnTmt7flkIjkvb/nlKgKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsIDQzMjYpCgpwb2ludHMgPC0gc2NvcmVzICU+JSBmaWx0ZXIoIWlzLm5hKExFNTApKQoKY29sb3JzIDwtIHBhbGV0dGVlcjo6cGFsZXR0ZWVyX2QoImdnc2NpOjpsZWdhY3lfdHJvbiIsNyxkaXJlY3Rpb249LTEsdHlwZT0iY29udGludW91cyIpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0id2hpdGUiLCBzaXplPTAuMSkgKwogIGdlb21fcG9pbnQoZGF0YT1wb2ludHMsIHNpemU9MC42LCBhZXMoeD1sb24sIHk9bGF0LCBjb2xvcj1MRTUwKSkgKwogIAogICMg6L+Z5Liq6Kej5Yaz5pa55qGI5piv55uu5qCH5pyA56iz5aal55qE6Kej5Yaz5pa55qGI5Y+C6ICDCiAgIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82NTYyNzE1My9zcGVjaWZ5LWJpbi1jb2xvdXJzLWluLWJpbm5lZC1jb2xvdXItZmlsbC1zY2FsZXMKICBiaW5uZWRfc2NhbGUoImNvbG9yIiwgImZvbyIsIGdncGxvdDI6OjpiaW5uZWRfcGFsKHNjYWxlczo6bWFudWFsX3BhbChjb2xvcnMpKSwKICAgICAgICAgICAgICAgZ3VpZGU9ImNvbG91cnN0ZXBzIiwgYnJlYWtzPWMoMC4wMDUsIDAuMDUsIDAuMSwgMC4xNSwgMC4yMCwgMC4yNSksCiAgICAgICAgICAgICAgIGxpbWl0cz1jKDAuMCwxLjApLCBzaG93LmxpbWl0cz1UUlVFKSArIAogICNndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMCkpKSArIAogIGNvb3JkX3NmKGNycz1zdF9jcnMoNDUwOCksIGV4cGFuZCA9IEZBTFNFLCB4bGltPWMoOTAsMTI0KSwgeWxpbT1jKDIwLCA0NCksIGRlZmF1bHQ9VFJVRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73lrprph4/pmY3msLTpooTmiqXor4TliIbliIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDPmnIjoh7MyMDIx5bm0MuaciOWFqOWbvTEwMjQ256uZ5pq06ZuoKD49NTBtbSlUU+ivhOWIhiIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTmF0aW9uYWwgTWV0ZW9yb2xvZ2ljYWwgQ2VudGVyIE5NQy1XRlQsIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTB9CgojIG1hcCBiYWNrZ3JvdW5kCmNoaW5hX21hcCA8LSBzdF9yZWFkKAogIHN5c3RlbS5maWxlKCJleHRkYXRhL2JvdTJfNHAuc2hwIiwgcGFja2FnZT0ibm1jTWV0UmVzb3VyY2VzIiksIAogIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsIHF1aWV0PVRSVUUpCmNoaW5hX21hcCA8LSBzdF9zZXRfY3JzKGNoaW5hX21hcCw0MzI2KQpjaGluYV9tYXAgPC0gc3RfY3JvcChjaGluYV9tYXAsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpjaGluYV9tYXAgPC0gc3RfdHJhbnNmb3JtKGNoaW5hX21hcCwgNDUwOCkKCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDAuMDEsIDAuMSwgMC4yLCAwLjQsIDAuNiwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRMRTUwKSkgJT4lCiAgbXV0YXRlKExFNTA9Y3V0KExFNTAsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCgoKdmFsdWVzIDwtIGMoIkdyYXkiLCIjRjZGOTY0IiwiIzAwNzUwMCIsImJsdWUiLCJtYWdlbnRhIiwiI0YwMTQwMCIpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJExFNTApCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPUxFNTAsIGNvbG9yPUxFNTApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciDHml6Xoh7MyMDIx5bm0MuaciDI45pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjmmrTpm6goPj01MG1tKVRT6K+E5YiGIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgNTAsIDYwLCA3MCwgODAsIDkwLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJFJhaW5Pck5vdCkpICU+JQogIG11dGF0ZShSYWluT3JOb3Q9Y3V0KFJhaW5Pck5vdCxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSByZXYoYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJykpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJFJhaW5Pck5vdCkKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9UmFpbk9yTm90LCBjb2xvcj1SYWluT3JOb3QpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciDHml6Xoh7MyMDIx5bm0MuaciDI45pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjmmbTpm6jlh4bnoa7njofor4TliIYoJSkiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCmBgYAoKIyMg5ZCE5Liq5a2j6IqC55qE6ZmN5rC06aKE5oql6LSo6YePCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTB9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojCiMgIOaYpeWto+mihOaKpei0qOmHjwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKCiMKIyAg6K+75YWl5pWw5o2u5paH5Lu2CgojIHRoZSBzY29yZSBkYXRhCmZpbGUgPC0gIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvcmVzdWx0L3JhaW4yNC9TQ01PQy8yMDIwMDMwMS0yMDIwMDUzMTAwLjAyNCIKCiMg6K+75YWl5pWw5o2uLCBJROS4uuWtl+espuWeiywg5Lul5L6/5LiOc3RhdGlvbl9pbmZv5a+55bqULgpjb2xfbmFtZXMgPC0gYygiSUQiLCAi5bCP6ZuoIiwgIuS4rembqCIsICLlpKfpm6giLCAi5pq06ZuoIiwgIuWkp+aatOmbqCIsICLnibnlpKfmmrTpm6giLAogICAgICAgICAgICAgIuWwj+mbqiIsICLkuK3pm6oiLCAi5aSn6ZuqIiwgIuaatOmbqiIsIAogICAgICAgICAgICAgIkxFMHAxIiwgIkxFMTAiLCAiTEUyNSIsICJMRTUwIiwgIkxFMTAwIiwgIkxFMjUwIiwKICAgICAgICAgICAgICLkuIDoiKzmgKfpmY3msLQiLCAi5pq06Zuo6Zuq5Lul5LiKIiwgIlJhaW5Pck5vdCIpCmNvbF90eXBlcz1jb2xzKC5kZWZhdWx0ID0gY29sX2RvdWJsZSgpLCAiSUQiPWNvbF9jaGFyYWN0ZXIoKSkKc2NvcmVzIDwtICByZWFkX2RlbGltKGZpbGUsIGRlbGltPSJcdCIsIGNvbF9uYW1lcz1jb2xfbmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICBuYT1jKCItLSIsICI5OTkuOTAwMDI0IiksIGNvbF90eXBlcz1jb2xfdHlwZXMpCgojIOWPquS9v+eUqOWQjumdouWHoOWIl+eahOaVsOaNriwg5bm257uT5ZCI56uZ54K557uP57qs5bqm5L+h5oGvCnNjb3JlcyA8LSBzY29yZXMgJT4lIHNlbGVjdCgKICAiSUQiLCAiTEUwcDEiLCAiTEUxMCIsICJMRTI1IiwgIkxFNTAiLCAiTEUxMDAiLCAiTEUyNTAiLCAiUmFpbk9yTm90IikgJT4lCiAgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgoKIwojICDnu5jliLblvLrpmY3msLTpooTmiqXotKjph4/liIbluIPlm74KCiMgbWFwIGJhY2tncm91bmQKY2hpbmFfbWFwIDwtIHN0X3JlYWQoCiAgc3lzdGVtLmZpbGUoImV4dGRhdGEvYm91Ml80cC5zaHAiLCBwYWNrYWdlPSJubWNNZXRSZXNvdXJjZXMiKSwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcXVpZXQ9VFJVRSkKY2hpbmFfbWFwIDwtIHN0X3NldF9jcnMoY2hpbmFfbWFwLDQzMjYpCmNoaW5hX21hcCA8LSBzdF9jcm9wKGNoaW5hX21hcCwgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCmNoaW5hX21hcCA8LSBzdF90cmFuc2Zvcm0oY2hpbmFfbWFwLCA0NTA4KQoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgMC4wMSwgMC4xLCAwLjIsIDAuNCwgMC42LCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJExFMjUpKSAlPiUKICBtdXRhdGUoTEU1MD1jdXQoTEUyNSxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCgp2YWx1ZXMgPC0gYygiR3JheSIsIiNGNkY5NjQiLCIjMDA3NTAwIiwiYmx1ZSIsIm1hZ2VudGEiLCIjRjAxNDAwIikKbGFiZWxzIDwtIGxldmVscyhwb2ludHMkTEU1MCkKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9TEU1MCwgY29sb3I9TEU1MCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBsYWJlbHM9bGFiZWxzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBsYWJlbHM9bGFiZWxzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95a6a6YeP6ZmN5rC06aKE5oql6K+E5YiG5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQz5pyIMeaXpeiHszIwMjDlubQ15pyIMzHml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOWkp+mbqCg+PTI1bW0pVFPor4TliIYiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCgojCiMgIOe7mOWItuaZtOmbqOmihOaKpei0qOmHj+WIhuW4g+WbvgoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgNTAsIDYwLCA3MCwgODAsIDkwLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJFJhaW5Pck5vdCkpICU+JQogIG11dGF0ZShSYWluT3JOb3Q9Y3V0KFJhaW5Pck5vdCxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSByZXYoYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJykpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJFJhaW5Pck5vdCkKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9UmFpbk9yTm90LCBjb2xvcj1SYWluT3JOb3QpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciDHml6Xoh7MyMDIw5bm0NeaciDMx5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjmmbTpm6jlh4bnoa7njofor4TliIYiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEwfQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIwojICDlpI/lraPpooTmiqXotKjph48KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCgojCiMgIOivu+WFpeaVsOaNruaWh+S7tgoKIyB0aGUgc2NvcmUgZGF0YQpmaWxlIDwtICIuL2RhdGEvZm9yZWNhc3Rfc2NvcmVzL3Jlc3VsdC9yYWluMjQvU0NNT0MvMjAyMDA2MDEtMjAyMDA4MzEwMC4wMjQiCgojIOivu+WFpeaVsOaNriwgSUTkuLrlrZfnrKblnossIOS7peS+v+S4jnN0YXRpb25faW5mb+WvueW6lC4KY29sX25hbWVzIDwtIGMoIklEIiwgIuWwj+mbqCIsICLkuK3pm6giLCAi5aSn6ZuoIiwgIuaatOmbqCIsICLlpKfmmrTpm6giLCAi54m55aSn5pq06ZuoIiwKICAgICAgICAgICAgICLlsI/pm6oiLCAi5Lit6ZuqIiwgIuWkp+mbqiIsICLmmrTpm6oiLCAKICAgICAgICAgICAgICJMRTBwMSIsICJMRTEwIiwgIkxFMjUiLCAiTEU1MCIsICJMRTEwMCIsICJMRTI1MCIsCiAgICAgICAgICAgICAi5LiA6Iis5oCn6ZmN5rC0IiwgIuaatOmbqOmbquS7peS4iiIsICJSYWluT3JOb3QiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiLS0iLCAiOTk5LjkwMDAyNCIpLCBjb2xfdHlwZXM9Y29sX3R5cGVzKQoKIyDlj6rkvb/nlKjlkI7pnaLlh6DliJfnmoTmlbDmja4sIOW5tue7k+WQiOermeeCuee7j+e6rOW6puS/oeaBrwpzY29yZXMgPC0gc2NvcmVzICU+JSBzZWxlY3QoCiAgIklEIiwgIkxFMHAxIiwgIkxFMTAiLCAiTEUyNSIsICJMRTUwIiwgIkxFMTAwIiwgIkxFMjUwIiwgIlJhaW5Pck5vdCIpICU+JQogIGlubmVyX2pvaW4oc3RhdGlvbl9pbmZvLCBieT0iSUQiKQoKCiMKIyAg57uY5Yi25by66ZmN5rC06aKE5oql6LSo6YeP5YiG5biD5Zu+CgojIG1hcCBiYWNrZ3JvdW5kCmNoaW5hX21hcCA8LSBzdF9yZWFkKAogIHN5c3RlbS5maWxlKCJleHRkYXRhL2JvdTJfNHAuc2hwIiwgcGFja2FnZT0ibm1jTWV0UmVzb3VyY2VzIiksIAogIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsIHF1aWV0PVRSVUUpCmNoaW5hX21hcCA8LSBzdF9zZXRfY3JzKGNoaW5hX21hcCw0MzI2KQpjaGluYV9tYXAgPC0gc3RfY3JvcChjaGluYV9tYXAsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpjaGluYV9tYXAgPC0gc3RfdHJhbnNmb3JtKGNoaW5hX21hcCwgNDUwOCkKCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDAuMDEsIDAuMSwgMC4yLCAwLjQsIDAuNiwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRMRTUwKSkgJT4lCiAgbXV0YXRlKExFNTA9Y3V0KExFNTAsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCgoKdmFsdWVzIDwtIGMoIkdyYXkiLCIjRjZGOTY0IiwiIzAwNzUwMCIsImJsdWUiLCJtYWdlbnRhIiwiI0YwMTQwMCIpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJExFNTApCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPUxFNTAsIGNvbG9yPUxFNTApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpeivhOWIhuWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0NuaciDHml6Xoh7MyMDIw5bm0OOaciDMx5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjmmrTpm6goPj01MG1tKVRT6K+E5YiGIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQoKIwojICDnu5jliLbmmbTpm6jpooTmiqXotKjph4/liIbluIPlm74KCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDUwLCA2MCwgNzAsIDgwLCA5MCwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRSYWluT3JOb3QpKSAlPiUKICBtdXRhdGUoUmFpbk9yTm90PWN1dChSYWluT3JOb3QsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCgp2YWx1ZXMgPC0gcmV2KGMoJyNlNDFhMWMnLCcjMzc3ZWI4JywnIzRkYWY0YScsJyM5ODRlYTMnLCcjZmY3ZjAwJywnI2ZmZmYzMycpKQpsYWJlbHMgPC0gbGV2ZWxzKHBvaW50cyRSYWluT3JOb3QpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPVJhaW5Pck5vdCwgY29sb3I9UmFpbk9yTm90KSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGxhYmVscz1sYWJlbHMsIGRyb3A9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGxhYmVscz1sYWJlbHMsIGRyb3A9RkFMU0UpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MTIpKSkgKyAKICBjb29yZF9zZihleHBhbmQgPSBGQUxTRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73lrprph4/pmY3msLTpooTmiqXotKjph4/liIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDbmnIgx5pel6IezMjAyMOW5tDjmnIgzMeaXpeWFqOWbvTEwMjQ256uZMjRo5pe25pWI5pm06Zuo5YeG56Gu546H6K+E5YiGIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMKIyAg56eL5a2j6aKE5oql6LSo6YePCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvcmFpbjI0L1NDTU9DLzIwMjAwOTAxLTIwMjAxMTMwMDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICLlsI/pm6giLCAi5Lit6ZuoIiwgIuWkp+mbqCIsICLmmrTpm6giLCAi5aSn5pq06ZuoIiwgIueJueWkp+aatOmbqCIsCiAgICAgICAgICAgICAi5bCP6ZuqIiwgIuS4rembqiIsICLlpKfpm6oiLCAi5pq06ZuqIiwgCiAgICAgICAgICAgICAiTEUwcDEiLCAiTEUxMCIsICJMRTI1IiwgIkxFNTAiLCAiTEUxMDAiLCAiTEUyNTAiLAogICAgICAgICAgICAgIuS4gOiIrOaAp+mZjeawtCIsICLmmrTpm6jpm6rku6XkuIoiLCAiUmFpbk9yTm90IikKY29sX3R5cGVzPWNvbHMoLmRlZmF1bHQgPSBjb2xfZG91YmxlKCksICJJRCI9Y29sX2NoYXJhY3RlcigpKQpzY29yZXMgPC0gIHJlYWRfZGVsaW0oZmlsZSwgZGVsaW09Ilx0IiwgY29sX25hbWVzPWNvbF9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgIG5hPWMoIi0tIiwgIjk5OS45MDAwMjQiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgc2VsZWN0KAogICJJRCIsICJMRTBwMSIsICJMRTEwIiwgIkxFMjUiLCAiTEU1MCIsICJMRTEwMCIsICJMRTI1MCIsICJSYWluT3JOb3QiKSAlPiUKICBpbm5lcl9qb2luKHN0YXRpb25faW5mbywgYnk9IklEIikKCgojCiMgIOe7mOWItuW8uumZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAwLjAxLCAwLjEsIDAuMiwgMC40LCAwLjYsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkTEUyNSkpICU+JQogIG11dGF0ZShMRTUwPWN1dChMRTI1LGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQoKCnZhbHVlcyA8LSBjKCJHcmF5IiwiI0Y2Rjk2NCIsIiMwMDc1MDAiLCJibHVlIiwibWFnZW50YSIsIiNGMDE0MDAiKQpsYWJlbHMgPC0gbGV2ZWxzKHBvaW50cyRMRTUwKQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1MRTUwLCBjb2xvcj1MRTUwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGxhYmVscz1sYWJlbHMsIGRyb3A9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGxhYmVscz1sYWJlbHMsIGRyb3A9RkFMU0UpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MTIpKSkgKyAKICBjb29yZF9zZihleHBhbmQgPSBGQUxTRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73lrprph4/pmY3msLTpooTmiqXor4TliIbliIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDnmnIgx5pel6IezMjAyMOW5tDEx5pyIMzDml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOWkp+mbqCg+PTI1bW0pVFPor4TliIYiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCgojCiMgIOe7mOWItuaZtOmbqOmihOaKpei0qOmHj+WIhuW4g+WbvgoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgNTAsIDYwLCA3MCwgODAsIDkwLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJFJhaW5Pck5vdCkpICU+JQogIG11dGF0ZShSYWluT3JOb3Q9Y3V0KFJhaW5Pck5vdCxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSByZXYoYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJykpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJFJhaW5Pck5vdCkKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9UmFpbk9yTm90LCBjb2xvcj1SYWluT3JOb3QpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgbGFiZWxzPWxhYmVscywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0OeaciDHml6Xoh7MyMDIw5bm0MTHmnIgzMOaXpeWFqOWbvTEwMjQ256uZMjRo5pe25pWI5pm06Zuo5YeG56Gu546H6K+E5YiGIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMKIyAg5Yas5a2j6aKE5oql6LSo6YePCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvcmFpbjI0L1NDTU9DLzIwMjAxMjAxLTIwMjEwMjI4MDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICLlsI/pm6giLCAi5Lit6ZuoIiwgIuWkp+mbqCIsICLmmrTpm6giLCAi5aSn5pq06ZuoIiwgIueJueWkp+aatOmbqCIsCiAgICAgICAgICAgICAi5bCP6ZuqIiwgIuS4rembqiIsICLlpKfpm6oiLCAi5pq06ZuqIiwgCiAgICAgICAgICAgICAiTEUwcDEiLCAiTEUxMCIsICJMRTI1IiwgIkxFNTAiLCAiTEUxMDAiLCAiTEUyNTAiLAogICAgICAgICAgICAgIuS4gOiIrOaAp+mZjeawtCIsICLmmrTpm6jpm6rku6XkuIoiLCAiUmFpbk9yTm90IikKY29sX3R5cGVzPWNvbHMoLmRlZmF1bHQgPSBjb2xfZG91YmxlKCksICJJRCI9Y29sX2NoYXJhY3RlcigpKQpzY29yZXMgPC0gIHJlYWRfZGVsaW0oZmlsZSwgZGVsaW09Ilx0IiwgY29sX25hbWVzPWNvbF9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgIG5hPWMoIi0tIiwgIjk5OS45MDAwMjQiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgc2VsZWN0KAogICJJRCIsICJMRTBwMSIsICJMRTEwIiwgIkxFMjUiLCAiTEU1MCIsICJMRTEwMCIsICJMRTI1MCIsICJSYWluT3JOb3QiKSAlPiUKICBpbm5lcl9qb2luKHN0YXRpb25faW5mbywgYnk9IklEIikKCgojCiMgIOe7mOWItuW8uumZjeawtOmihOaKpei0qOmHj+WIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAwLjAxLCAwLjEsIDAuMiwgMC40LCAwLjYsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkTEUyNSkpICU+JQogIG11dGF0ZShMRTUwPWN1dChMRTI1LGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQoKdmFsdWVzIDwtIGMoIkdyYXkiLCIjRjZGOTY0IiwiIzAwNzUwMCIsImJsdWUiLCJtYWdlbnRhIiwiI0YwMTQwMCIpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJExFNTApCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPUxFNTAsIGNvbG9yPUxFNTApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveWumumHj+mZjeawtOmihOaKpeivhOWIhuWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0MTLmnIgx5pel6IezMjAyMeW5tDLmnIgyOOaXpeWFqOWbvTEwMjQ256uZMjRo5pe25pWI5aSn6ZuoKD49MjVtbSlUU+ivhOWIhiIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCiMKIyAg57uY5Yi25pm06Zuo6aKE5oql6LSo6YeP5YiG5biD5Zu+Cgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCA1MCwgNjAsIDcwLCA4MCwgOTAsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkUmFpbk9yTm90KSkgJT4lCiAgbXV0YXRlKFJhaW5Pck5vdD1jdXQoUmFpbk9yTm90LGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQoKdmFsdWVzIDwtIHJldihjKCcjZTQxYTFjJywnIzM3N2ViOCcsJyM0ZGFmNGEnLCcjOTg0ZWEzJywnI2ZmN2YwMCcsJyNmZmZmMzMnKSkKbGFiZWxzIDwtIGxldmVscyhwb2ludHMkUmFpbk9yTm90KQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1SYWluT3JOb3QsIGNvbG9yPVJhaW5Pck5vdCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBsYWJlbHM9bGFiZWxzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBsYWJlbHM9bGFiZWxzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95a6a6YeP6ZmN5rC06aKE5oql6LSo6YeP5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQxMuaciDHml6Xoh7MyMDIx5bm0MuaciDI45pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjmmbTpm6jlh4bnoa7njofor4TliIYiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCgpgYGAKCiMjIOmrmOa4qS/kvY7muKnpooTmiqXlh4bnoa7njocKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMKIyAg5YWo5bm06aKE5oql6LSo6YePCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvdG14LW5laWItaGVpZ2h0L1NDTU9DLzIwMjAwMzAxLTIwMjEwMjI4MDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICJNQUUiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiOTk5LjkiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgoKIwojICDnu5jliLbpq5jmuKnpooTmiqXor6/lt67liIbluIPlm74KCiMgbWFwIGJhY2tncm91bmQKY2hpbmFfbWFwIDwtIHN0X3JlYWQoCiAgc3lzdGVtLmZpbGUoImV4dGRhdGEvYm91Ml80cC5zaHAiLCBwYWNrYWdlPSJubWNNZXRSZXNvdXJjZXMiKSwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcXVpZXQ9VFJVRSkKY2hpbmFfbWFwIDwtIHN0X3NldF9jcnMoY2hpbmFfbWFwLDQzMjYpCmNoaW5hX21hcCA8LSBzdF9jcm9wKGNoaW5hX21hcCwgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCmNoaW5hX21hcCA8LSBzdF90cmFuc2Zvcm0oY2hpbmFfbWFwLCA0NTA4KQoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgMS4wLCAxLjQsIDEuNiwgMi4wLCAyLjUsIDMuMCwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRNQUUpKSAlPiUKICBtdXRhdGUoTUFFPWN1dChNQUUsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCnZhbHVlcyA8LSBjKCcjYTZjZWUzJywnIzFmNzhiNCcsJyNiMmRmOGEnLCcjMzNhMDJjJywnI2ZiOWE5OScsJyNlMzFhMWMnLCcjZmRiZjZmJykKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9TUFFLCBjb2xvcj1NQUUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveaXpeacgOmrmOawlOa4qemihOaKpeivr+W3ruWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciDHml6Xoh7MyMDIx5bm0MuaciDI45pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjml6XmnIDpq5jmuKnlubPlnYfnu53lr7nor6/lt64o5bqmKSIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvdG1pLW5laWItaGVpZ2h0L1NDTU9DLzIwMjAwMzAxLTIwMjEwMjI4MDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICJNQUUiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiLS0iLCAiOTk5LjkiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgojCiMgIOe7mOWItuS9jua4qemihOaKpeivr+W3ruWIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAxLjAsIDEuNCwgMS42LCAyLjAsIDIuNSwgMy4wLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJE1BRSkpICU+JQogIG11dGF0ZShNQUU9Y3V0KE1BRSxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSBjKCcjYTZjZWUzJywnIzFmNzhiNCcsJyNiMmRmOGEnLCcjMzNhMDJjJywnI2ZiOWE5OScsJyNlMzFhMWMnLCcjZmRiZjZmJykKbGFiZWxzIDwtIGxldmVscyhwb2ludHMkTUFFKQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1NQUUsIGNvbG9yPU1BRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95pel5pyA5L2O5rCU5rip6aKE5oql6K+v5beu5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQz5pyIMeaXpeiHszIwMjHlubQy5pyIMjjml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOaXpeacgOS9jua4qeW5s+Wdh+e7neWvueivr+W3rijluqYpIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0KCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMKIyAg5pil5a2j6aKE5oql6LSo6YePCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvdG14LW5laWItaGVpZ2h0L1NDTU9DLzIwMjAwMzAxLTIwMjAwNTMxMDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICJNQUUiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiOTk5LjkiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgoKIwojICDnu5jliLbpq5jmuKnpooTmiqXor6/lt67liIbluIPlm74KCiMgbWFwIGJhY2tncm91bmQKY2hpbmFfbWFwIDwtIHN0X3JlYWQoCiAgc3lzdGVtLmZpbGUoImV4dGRhdGEvYm91Ml80cC5zaHAiLCBwYWNrYWdlPSJubWNNZXRSZXNvdXJjZXMiKSwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcXVpZXQ9VFJVRSkKY2hpbmFfbWFwIDwtIHN0X3NldF9jcnMoY2hpbmFfbWFwLDQzMjYpCmNoaW5hX21hcCA8LSBzdF9jcm9wKGNoaW5hX21hcCwgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCmNoaW5hX21hcCA8LSBzdF90cmFuc2Zvcm0oY2hpbmFfbWFwLCA0NTA4KQoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgMS4wLCAxLjQsIDEuNiwgMi4wLCAyLjUsIDMuMCwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRNQUUpKSAlPiUKICBtdXRhdGUoTUFFPWN1dChNQUUsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCnZhbHVlcyA8LSBjKCcjYTZjZWUzJywnIzFmNzhiNCcsJyNiMmRmOGEnLCcjMzNhMDJjJywnI2ZiOWE5OScsJyNlMzFhMWMnLCcjZmRiZjZmJykKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9TUFFLCBjb2xvcj1NQUUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveaXpeacgOmrmOawlOa4qemihOaKpeivr+W3ruWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0M+aciDHml6Xoh7MyMDIw5bm0NeaciDMx5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjml6XmnIDpq5jmuKnlubPlnYfnu53lr7nor6/lt64o5bqmKSIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvdG1pLW5laWItaGVpZ2h0L1NDTU9DLzIwMjAwMzAxLTIwMjAwNTMxMDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICJNQUUiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiLS0iLCAiOTk5LjkiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgojCiMgIOe7mOWItuS9jua4qemihOaKpeivr+W3ruWIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAxLjAsIDEuNCwgMS42LCAyLjAsIDIuNSwgMy4wLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJE1BRSkpICU+JQogIG11dGF0ZShNQUU9Y3V0KE1BRSxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSBjKCcjYTZjZWUzJywnIzFmNzhiNCcsJyNiMmRmOGEnLCcjMzNhMDJjJywnI2ZiOWE5OScsJyNlMzFhMWMnLCcjZmRiZjZmJykKbGFiZWxzIDwtIGxldmVscyhwb2ludHMkTUFFKQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1NQUUsIGNvbG9yPU1BRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95pel5pyA5L2O5rCU5rip6aKE5oql6K+v5beu5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQz5pyIMeaXpeiHszIwMjDlubQ15pyIMzHml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOaXpeacgOS9jua4qeW5s+Wdh+e7neWvueivr+W3rijluqYpIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQoKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTB9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojCiMgIOWkj+Wto+mihOaKpei0qOmHjwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKCiMKIyAg6K+75YWl5pWw5o2u5paH5Lu2CgojIHRoZSBzY29yZSBkYXRhCmZpbGUgPC0gIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvcmVzdWx0L3RteC1uZWliLWhlaWdodC9TQ01PQy8yMDIwMDYwMS0yMDIwMDgzMTAwLjAyNCIKCiMg6K+75YWl5pWw5o2uLCBJROS4uuWtl+espuWeiywg5Lul5L6/5LiOc3RhdGlvbl9pbmZv5a+55bqULgpjb2xfbmFtZXMgPC0gYygiSUQiLCAiTUFFIikKY29sX3R5cGVzPWNvbHMoLmRlZmF1bHQgPSBjb2xfZG91YmxlKCksICJJRCI9Y29sX2NoYXJhY3RlcigpKQpzY29yZXMgPC0gIHJlYWRfZGVsaW0oZmlsZSwgZGVsaW09Ilx0IiwgY29sX25hbWVzPWNvbF9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgIG5hPWMoIjk5OS45IiksIGNvbF90eXBlcz1jb2xfdHlwZXMpCgojIOWPquS9v+eUqOWQjumdouWHoOWIl+eahOaVsOaNriwg5bm257uT5ZCI56uZ54K557uP57qs5bqm5L+h5oGvCnNjb3JlcyA8LSBzY29yZXMgJT4lIGlubmVyX2pvaW4oc3RhdGlvbl9pbmZvLCBieT0iSUQiKQoKCiMKIyAg57uY5Yi26auY5rip6aKE5oql6K+v5beu5YiG5biD5Zu+CgojIG1hcCBiYWNrZ3JvdW5kCmNoaW5hX21hcCA8LSBzdF9yZWFkKAogIHN5c3RlbS5maWxlKCJleHRkYXRhL2JvdTJfNHAuc2hwIiwgcGFja2FnZT0ibm1jTWV0UmVzb3VyY2VzIiksIAogIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsIHF1aWV0PVRSVUUpCmNoaW5hX21hcCA8LSBzdF9zZXRfY3JzKGNoaW5hX21hcCw0MzI2KQpjaGluYV9tYXAgPC0gc3RfY3JvcChjaGluYV9tYXAsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpjaGluYV9tYXAgPC0gc3RfdHJhbnNmb3JtKGNoaW5hX21hcCwgNDUwOCkKCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDEuMCwgMS40LCAxLjYsIDIuMCwgMi41LCAzLjAsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkTUFFKSkgJT4lCiAgbXV0YXRlKE1BRT1jdXQoTUFFLGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQp2YWx1ZXMgPC0gYygnI2E2Y2VlMycsJyMxZjc4YjQnLCcjYjJkZjhhJywnIzMzYTAyYycsJyNmYjlhOTknLCcjZTMxYTFjJywnI2ZkYmY2ZicpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPU1BRSwgY29sb3I9TUFFKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MTIpKSkgKyAKICBjb29yZF9zZihleHBhbmQgPSBGQUxTRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73ml6XmnIDpq5jmsJTmuKnpooTmiqXor6/lt67liIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDbmnIgx5pel6IezMjAyMOW5tDjmnIgzMeaXpeWFqOWbvTEwMjQ256uZMjRo5pe25pWI5pel5pyA6auY5rip5bmz5Z2H57ud5a+56K+v5beuKOW6pikiLAogICAgICAgY2FwdGlvbiA9ICJPcmlnaW46IE5NQy1XRlQg5qOA6aqM5aSn5pWw5o2u5YiG5p6Q5bmz5Y+wIChodHRwOi8vMTAuMS42NC4xNDYvbnZzbmV3KSIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPVRSVUUsIGJhc2Vfc2l6ZT0xMiwgCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZV9zaXplPTI0LCBzdWJ0aXRsZV9zaXplPTE4LCBjYXB0aW9uX3NpemU9MTIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCgoKCiMKIyAg6K+75YWl5pWw5o2u5paH5Lu2CgojIHRoZSBzY29yZSBkYXRhCmZpbGUgPC0gIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvcmVzdWx0L3RtaS1uZWliLWhlaWdodC9TQ01PQy8yMDIwMDYwMS0yMDIwMDgzMTAwLjAyNCIKCiMg6K+75YWl5pWw5o2uLCBJROS4uuWtl+espuWeiywg5Lul5L6/5LiOc3RhdGlvbl9pbmZv5a+55bqULgpjb2xfbmFtZXMgPC0gYygiSUQiLCAiTUFFIikKY29sX3R5cGVzPWNvbHMoLmRlZmF1bHQgPSBjb2xfZG91YmxlKCksICJJRCI9Y29sX2NoYXJhY3RlcigpKQpzY29yZXMgPC0gIHJlYWRfZGVsaW0oZmlsZSwgZGVsaW09Ilx0IiwgY29sX25hbWVzPWNvbF9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgIG5hPWMoIi0tIiwgIjk5OS45IiksIGNvbF90eXBlcz1jb2xfdHlwZXMpCgojIOWPquS9v+eUqOWQjumdouWHoOWIl+eahOaVsOaNriwg5bm257uT5ZCI56uZ54K557uP57qs5bqm5L+h5oGvCnNjb3JlcyA8LSBzY29yZXMgJT4lIGlubmVyX2pvaW4oc3RhdGlvbl9pbmZvLCBieT0iSUQiKQoKIwojICDnu5jliLbkvY7muKnpooTmiqXor6/lt67liIbluIPlm74KCiMgbWFwIGJhY2tncm91bmQKY2hpbmFfbWFwIDwtIHN0X3JlYWQoCiAgc3lzdGVtLmZpbGUoImV4dGRhdGEvYm91Ml80cC5zaHAiLCBwYWNrYWdlPSJubWNNZXRSZXNvdXJjZXMiKSwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcXVpZXQ9VFJVRSkKY2hpbmFfbWFwIDwtIHN0X3NldF9jcnMoY2hpbmFfbWFwLDQzMjYpCmNoaW5hX21hcCA8LSBzdF9jcm9wKGNoaW5hX21hcCwgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCmNoaW5hX21hcCA8LSBzdF90cmFuc2Zvcm0oY2hpbmFfbWFwLCA0NTA4KQoKcG9pbnRzIDwtIHN0X2FzX3NmKHNjb3JlcywgY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnM9NDMyNikKYnJlYWtzIDwtIGMoLUluZiwgMS4wLCAxLjQsIDEuNiwgMi4wLCAyLjUsIDMuMCwgSW5mKQpwb2ludHMgPC0gZmlsdGVyKHBvaW50cywgIWlzLm5hKHBvaW50cyRNQUUpKSAlPiUKICBtdXRhdGUoTUFFPWN1dChNQUUsYnJlYWtzLHJpZ2h0PUZBTFNFKSkKcG9pbnRzIDwtIHN0X2Nyb3AocG9pbnRzLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKcG9pbnRzIDwtIHN0X3RyYW5zZm9ybShwb2ludHMsIDQ1MDgpCgp2YWx1ZXMgPC0gYygnI2E2Y2VlMycsJyMxZjc4YjQnLCcjYjJkZjhhJywnIzMzYTAyYycsJyNmYjlhOTknLCcjZTMxYTFjJywnI2ZkYmY2ZicpCmxhYmVscyA8LSBsZXZlbHMocG9pbnRzJE1BRSkKCmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGE9Y2hpbmFfbWFwLCBmaWxsPSJhbnRpcXVld2hpdGUxIikgKwogIGdlb21fc2YoZGF0YT1wb2ludHMsIHNoYXBlPTIzLCBzaXplPTAuNiwgYWxwaGE9MC44LAogICAgICAgICAgYWVzKGZpbGw9TUFFLCBjb2xvcj1NQUUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPXZhbHVlcywgZHJvcD1GQUxTRSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT0xMikpKSArIAogIGNvb3JkX3NmKGV4cGFuZCA9IEZBTFNFKSArCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJibCIsIHdpZHRoX2hpbnQgPSAwLjMpICsKICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJsIiwgd2hpY2hfbm9ydGggPSAidHJ1ZSIsIAogICAgICBwYWRfeCA9IHVuaXQoMC43NSwgImluIiksIHBhZF95ID0gdW5pdCgwLjUsICJpbiIpLAogICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gTlVMTCwKICAgICAgIHRpdGxlID0gIuWFqOWbveaXpeacgOS9juawlOa4qemihOaKpeivr+W3ruWIhuW4g+WbviIsCiAgICAgICBzdWJ0aXRsZSA9ICIyMDIw5bm0NuaciDHml6Xoh7MyMDIw5bm0OOaciDMx5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjml6XmnIDkvY7muKnlubPlnYfnu53lr7nor6/lt64o5bqmKSIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEwfQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIwojICDnp4vlraPpooTmiqXotKjph48KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCgojCiMgIOivu+WFpeaVsOaNruaWh+S7tgoKIyB0aGUgc2NvcmUgZGF0YQpmaWxlIDwtICIuL2RhdGEvZm9yZWNhc3Rfc2NvcmVzL3Jlc3VsdC90bXgtbmVpYi1oZWlnaHQvU0NNT0MvMjAyMDA5MDEtMjAyMDExMzAwMC4wMjQiCgojIOivu+WFpeaVsOaNriwgSUTkuLrlrZfnrKblnossIOS7peS+v+S4jnN0YXRpb25faW5mb+WvueW6lC4KY29sX25hbWVzIDwtIGMoIklEIiwgIk1BRSIpCmNvbF90eXBlcz1jb2xzKC5kZWZhdWx0ID0gY29sX2RvdWJsZSgpLCAiSUQiPWNvbF9jaGFyYWN0ZXIoKSkKc2NvcmVzIDwtICByZWFkX2RlbGltKGZpbGUsIGRlbGltPSJcdCIsIGNvbF9uYW1lcz1jb2xfbmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICBuYT1jKCI5OTkuOSIpLCBjb2xfdHlwZXM9Y29sX3R5cGVzKQoKIyDlj6rkvb/nlKjlkI7pnaLlh6DliJfnmoTmlbDmja4sIOW5tue7k+WQiOermeeCuee7j+e6rOW6puS/oeaBrwpzY29yZXMgPC0gc2NvcmVzICU+JSBpbm5lcl9qb2luKHN0YXRpb25faW5mbywgYnk9IklEIikKCgojCiMgIOe7mOWItumrmOa4qemihOaKpeivr+W3ruWIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAxLjAsIDEuNCwgMS42LCAyLjAsIDIuNSwgMy4wLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJE1BRSkpICU+JQogIG11dGF0ZShNQUU9Y3V0KE1BRSxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKdmFsdWVzIDwtIGMoJyNhNmNlZTMnLCcjMWY3OGI0JywnI2IyZGY4YScsJyMzM2EwMmMnLCcjZmI5YTk5JywnI2UzMWExYycsJyNmZGJmNmYnKQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1NQUUsIGNvbG9yPU1BRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95pel5pyA6auY5rCU5rip6aKE5oql6K+v5beu5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQ55pyIMeaXpeiHszIwMjDlubQxMeaciDMw5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjml6XmnIDpq5jmuKnlubPlnYfnu53lr7nor6/lt64o5bqmKSIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKCgoKIwojICDor7vlhaXmlbDmja7mlofku7YKCiMgdGhlIHNjb3JlIGRhdGEKZmlsZSA8LSAiLi9kYXRhL2ZvcmVjYXN0X3Njb3Jlcy9yZXN1bHQvdG1pLW5laWItaGVpZ2h0L1NDTU9DLzIwMjAwOTAxLTIwMjAxMTMwMDAuMDI0IgoKIyDor7vlhaXmlbDmja4sIElE5Li65a2X56ym5Z6LLCDku6Xkvr/kuI5zdGF0aW9uX2luZm/lr7nlupQuCmNvbF9uYW1lcyA8LSBjKCJJRCIsICJNQUUiKQpjb2xfdHlwZXM9Y29scyguZGVmYXVsdCA9IGNvbF9kb3VibGUoKSwgIklEIj1jb2xfY2hhcmFjdGVyKCkpCnNjb3JlcyA8LSAgcmVhZF9kZWxpbShmaWxlLCBkZWxpbT0iXHQiLCBjb2xfbmFtZXM9Y29sX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgbmE9YygiLS0iLCAiOTk5LjkiKSwgY29sX3R5cGVzPWNvbF90eXBlcykKCiMg5Y+q5L2/55So5ZCO6Z2i5Yeg5YiX55qE5pWw5o2uLCDlubbnu5PlkIjnq5nngrnnu4/nuqzluqbkv6Hmga8Kc2NvcmVzIDwtIHNjb3JlcyAlPiUgaW5uZXJfam9pbihzdGF0aW9uX2luZm8sIGJ5PSJJRCIpCgojCiMgIOe7mOWItuS9jua4qemihOaKpeivr+W3ruWIhuW4g+WbvgoKIyBtYXAgYmFja2dyb3VuZApjaGluYV9tYXAgPC0gc3RfcmVhZCgKICBzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9ib3UyXzRwLnNocCIsIHBhY2thZ2U9Im5tY01ldFJlc291cmNlcyIpLCAKICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCBxdWlldD1UUlVFKQpjaGluYV9tYXAgPC0gc3Rfc2V0X2NycyhjaGluYV9tYXAsNDMyNikKY2hpbmFfbWFwIDwtIHN0X2Nyb3AoY2hpbmFfbWFwLCB4bWluPTczLCB4bWF4PTEzNSwgeW1pbj0xNywgeW1heD01NCkKY2hpbmFfbWFwIDwtIHN0X3RyYW5zZm9ybShjaGluYV9tYXAsIDQ1MDgpCgpwb2ludHMgPC0gc3RfYXNfc2Yoc2NvcmVzLCBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksIGNycz00MzI2KQpicmVha3MgPC0gYygtSW5mLCAxLjAsIDEuNCwgMS42LCAyLjAsIDIuNSwgMy4wLCBJbmYpCnBvaW50cyA8LSBmaWx0ZXIocG9pbnRzLCAhaXMubmEocG9pbnRzJE1BRSkpICU+JQogIG11dGF0ZShNQUU9Y3V0KE1BRSxicmVha3MscmlnaHQ9RkFMU0UpKQpwb2ludHMgPC0gc3RfY3JvcChwb2ludHMsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpwb2ludHMgPC0gc3RfdHJhbnNmb3JtKHBvaW50cywgNDUwOCkKCnZhbHVlcyA8LSBjKCcjYTZjZWUzJywnIzFmNzhiNCcsJyNiMmRmOGEnLCcjMzNhMDJjJywnI2ZiOWE5OScsJyNlMzFhMWMnLCcjZmRiZjZmJykKbGFiZWxzIDwtIGxldmVscyhwb2ludHMkTUFFKQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1jaGluYV9tYXAsIGZpbGw9ImFudGlxdWV3aGl0ZTEiKSArCiAgZ2VvbV9zZihkYXRhPXBvaW50cywgc2hhcGU9MjMsIHNpemU9MC42LCBhbHBoYT0wLjgsCiAgICAgICAgICBhZXMoZmlsbD1NQUUsIGNvbG9yPU1BRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT1OVUxMLCB2YWx1ZXM9dmFsdWVzLCBkcm9wPUZBTFNFKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXM9bGlzdChzaXplPTEyKSkpICsgCiAgY29vcmRfc2YoZXhwYW5kID0gRkFMU0UpICsKICBhbm5vdGF0aW9uX3NjYWxlKGxvY2F0aW9uID0gImJsIiwgd2lkdGhfaGludCA9IDAuMykgKwogIGFubm90YXRpb25fbm9ydGhfYXJyb3cobG9jYXRpb24gPSAiYmwiLCB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgCiAgICAgIHBhZF94ID0gdW5pdCgwLjc1LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuNSwgImluIiksCiAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLAogICAgICAgdGl0bGUgPSAi5YWo5Zu95pel5pyA5L2O5rCU5rip6aKE5oql6K+v5beu5YiG5biD5Zu+IiwKICAgICAgIHN1YnRpdGxlID0gIjIwMjDlubQ55pyIMeaXpeiHszIwMjDlubQxMeaciDMw5pel5YWo5Zu9MTAyNDbnq5kyNGjml7bmlYjml6XmnIDkvY7muKnlubPlnYfnu53lr7nor6/lt64o5bqmKSIsCiAgICAgICBjYXB0aW9uID0gIk9yaWdpbjogTk1DLVdGVCDmo4DpqozlpKfmlbDmja7liIbmnpDlubPlj7AgKGh0dHA6Ly8xMC4xLjY0LjE0Ni9udnNuZXcpIikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9VFJVRSwgYmFzZV9zaXplPTEyLCAKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlX3NpemU9MjQsIHN1YnRpdGxlX3NpemU9MTgsIGNhcHRpb25fc2l6ZT0xMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTB9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojCiMgIOWGrOWto+mihOaKpei0qOmHjwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKCiMKIyAg6K+75YWl5pWw5o2u5paH5Lu2CgojIHRoZSBzY29yZSBkYXRhCmZpbGUgPC0gIi4vZGF0YS9mb3JlY2FzdF9zY29yZXMvcmVzdWx0L3RteC1uZWliLWhlaWdodC9TQ01PQy8yMDIwMTIwMS0yMDIxMDIyODAwLjAyNCIKCiMg6K+75YWl5pWw5o2uLCBJROS4uuWtl+espuWeiywg5Lul5L6/5LiOc3RhdGlvbl9pbmZv5a+55bqULgpjb2xfbmFtZXMgPC0gYygiSUQiLCAiTUFFIikKY29sX3R5cGVzPWNvbHMoLmRlZmF1bHQgPSBjb2xfZG91YmxlKCksICJJRCI9Y29sX2NoYXJhY3RlcigpKQpzY29yZXMgPC0gIHJlYWRfZGVsaW0oZmlsZSwgZGVsaW09Ilx0IiwgY29sX25hbWVzPWNvbF9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgIG5hPWMoIjk5OS45IiksIGNvbF90eXBlcz1jb2xfdHlwZXMpCgojIOWPquS9v+eUqOWQjumdouWHoOWIl+eahOaVsOaNriwg5bm257uT5ZCI56uZ54K557uP57qs5bqm5L+h5oGvCnNjb3JlcyA8LSBzY29yZXMgJT4lIGlubmVyX2pvaW4oc3RhdGlvbl9pbmZvLCBieT0iSUQiKQoKCiMKIyAg57uY5Yi26auY5rip6aKE5oql6K+v5beu5YiG5biD5Zu+CgojIG1hcCBiYWNrZ3JvdW5kCmNoaW5hX21hcCA8LSBzdF9yZWFkKAogIHN5c3RlbS5maWxlKCJleHRkYXRhL2JvdTJfNHAuc2hwIiwgcGFja2FnZT0ibm1jTWV0UmVzb3VyY2VzIiksIAogIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsIHF1aWV0PVRSVUUpCmNoaW5hX21hcCA8LSBzdF9zZXRfY3JzKGNoaW5hX21hcCw0MzI2KQpjaGluYV9tYXAgPC0gc3RfY3JvcChjaGluYV9tYXAsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpjaGluYV9tYXAgPC0gc3RfdHJhbnNmb3JtKGNoaW5hX21hcCwgNDUwOCkKCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDEuMCwgMS40LCAxLjYsIDIuMCwgMi41LCAzLjAsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkTUFFKSkgJT4lCiAgbXV0YXRlKE1BRT1jdXQoTUFFLGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQp2YWx1ZXMgPC0gYygnI2E2Y2VlMycsJyMxZjc4YjQnLCcjYjJkZjhhJywnIzMzYTAyYycsJyNmYjlhOTknLCcjZTMxYTFjJywnI2ZkYmY2ZicpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPU1BRSwgY29sb3I9TUFFKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MTIpKSkgKyAKICBjb29yZF9zZihleHBhbmQgPSBGQUxTRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73ml6XmnIDpq5jmsJTmuKnpooTmiqXor6/lt67liIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDEy5pyIMeaXpeiHszIwMjHlubQy5pyIMjjml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOaXpeacgOmrmOa4qeW5s+Wdh+e7neWvueivr+W3rijluqYpIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQoKCgojCiMgIOivu+WFpeaVsOaNruaWh+S7tgoKIyB0aGUgc2NvcmUgZGF0YQpmaWxlIDwtICIuL2RhdGEvZm9yZWNhc3Rfc2NvcmVzL3Jlc3VsdC90bWktbmVpYi1oZWlnaHQvU0NNT0MvMjAyMDEyMDEtMjAyMTAyMjgwMC4wMjQiCgojIOivu+WFpeaVsOaNriwgSUTkuLrlrZfnrKblnossIOS7peS+v+S4jnN0YXRpb25faW5mb+WvueW6lC4KY29sX25hbWVzIDwtIGMoIklEIiwgIk1BRSIpCmNvbF90eXBlcz1jb2xzKC5kZWZhdWx0ID0gY29sX2RvdWJsZSgpLCAiSUQiPWNvbF9jaGFyYWN0ZXIoKSkKc2NvcmVzIDwtICByZWFkX2RlbGltKGZpbGUsIGRlbGltPSJcdCIsIGNvbF9uYW1lcz1jb2xfbmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICBuYT1jKCItLSIsICI5OTkuOSIpLCBjb2xfdHlwZXM9Y29sX3R5cGVzKQoKIyDlj6rkvb/nlKjlkI7pnaLlh6DliJfnmoTmlbDmja4sIOW5tue7k+WQiOermeeCuee7j+e6rOW6puS/oeaBrwpzY29yZXMgPC0gc2NvcmVzICU+JSBpbm5lcl9qb2luKHN0YXRpb25faW5mbywgYnk9IklEIikKCiMKIyAg57uY5Yi25L2O5rip6aKE5oql6K+v5beu5YiG5biD5Zu+CgojIG1hcCBiYWNrZ3JvdW5kCmNoaW5hX21hcCA8LSBzdF9yZWFkKAogIHN5c3RlbS5maWxlKCJleHRkYXRhL2JvdTJfNHAuc2hwIiwgcGFja2FnZT0ibm1jTWV0UmVzb3VyY2VzIiksIAogIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsIHF1aWV0PVRSVUUpCmNoaW5hX21hcCA8LSBzdF9zZXRfY3JzKGNoaW5hX21hcCw0MzI2KQpjaGluYV9tYXAgPC0gc3RfY3JvcChjaGluYV9tYXAsIHhtaW49NzMsIHhtYXg9MTM1LCB5bWluPTE3LCB5bWF4PTU0KQpjaGluYV9tYXAgPC0gc3RfdHJhbnNmb3JtKGNoaW5hX21hcCwgNDUwOCkKCnBvaW50cyA8LSBzdF9hc19zZihzY29yZXMsIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzPTQzMjYpCmJyZWFrcyA8LSBjKC1JbmYsIDEuMCwgMS40LCAxLjYsIDIuMCwgMi41LCAzLjAsIEluZikKcG9pbnRzIDwtIGZpbHRlcihwb2ludHMsICFpcy5uYShwb2ludHMkTUFFKSkgJT4lCiAgbXV0YXRlKE1BRT1jdXQoTUFFLGJyZWFrcyxyaWdodD1GQUxTRSkpCnBvaW50cyA8LSBzdF9jcm9wKHBvaW50cywgeG1pbj03MywgeG1heD0xMzUsIHltaW49MTcsIHltYXg9NTQpCnBvaW50cyA8LSBzdF90cmFuc2Zvcm0ocG9pbnRzLCA0NTA4KQoKdmFsdWVzIDwtIGMoJyNhNmNlZTMnLCcjMWY3OGI0JywnI2IyZGY4YScsJyMzM2EwMmMnLCcjZmI5YTk5JywnI2UzMWExYycsJyNmZGJmNmYnKQpsYWJlbHMgPC0gbGV2ZWxzKHBvaW50cyRNQUUpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPWNoaW5hX21hcCwgZmlsbD0iYW50aXF1ZXdoaXRlMSIpICsKICBnZW9tX3NmKGRhdGE9cG9pbnRzLCBzaGFwZT0yMywgc2l6ZT0wLjYsIGFscGhhPTAuOCwKICAgICAgICAgIGFlcyhmaWxsPU1BRSwgY29sb3I9TUFFKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIHZhbHVlcz12YWx1ZXMsIGRyb3A9RkFMU0UpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MTIpKSkgKyAKICBjb29yZF9zZihleHBhbmQgPSBGQUxTRSkgKwogIGFubm90YXRpb25fc2NhbGUobG9jYXRpb24gPSAiYmwiLCB3aWR0aF9oaW50ID0gMC4zKSArCiAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJibCIsIHdoaWNoX25vcnRoID0gInRydWUiLCAKICAgICAgcGFkX3ggPSB1bml0KDAuNzUsICJpbiIpLCBwYWRfeSA9IHVuaXQoMC41LCAiaW4iKSwKICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19mYW5jeV9vcmllbnRlZXJpbmcpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IE5VTEwsCiAgICAgICB0aXRsZSA9ICLlhajlm73ml6XmnIDkvY7msJTmuKnpooTmiqXor6/lt67liIbluIPlm74iLAogICAgICAgc3VidGl0bGUgPSAiMjAyMOW5tDEy5pyIMeaXpeiHszIwMjHlubQy5pyIMjjml6Xlhajlm70xMDI0NuermTI0aOaXtuaViOaXpeacgOS9jua4qeW5s+Wdh+e7neWvueivr+W3rijluqYpIiwKICAgICAgIGNhcHRpb24gPSAiT3JpZ2luOiBOTUMtV0ZUIOajgOmqjOWkp+aVsOaNruWIhuaekOW5s+WPsCAoaHR0cDovLzEwLjEuNjQuMTQ2L252c25ldykiKSArCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD1UUlVFLCBiYXNlX3NpemU9MTIsIAogICAgICAgICAgICAgICAgIHBsb3RfdGl0bGVfc2l6ZT0yNCwgc3VidGl0bGVfc2l6ZT0xOCwgY2FwdGlvbl9zaXplPTEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQoKYGBgCg==